from Tkinter import *
from array import *
import Image
import ImageTk
import _chaos

MIN_DELTA = 1*10**(-17)

class OrbitDiagram:

    def __init__(self, width=600, height=400, start=50, stop=300, c0=-2.0, c1 = 0.25):
        self.width, self.height = width, height
        self.image=None
        self.c_value = array('d', range(self.width))
        self.window = Tk()
        self.canvas = Canvas(self.window, width=width, height=height, cursor='plus')
        self.canvas.bind("<Motion>", self.motion)
        self.canvas.bind("<Leave>", self.leave)
        self.canvas.bind("<Button-1>", self.mouse_down)
        self.canvas.bind("<ButtonRelease-1>", self.mouse_up)
        self.canvas.bind("<ButtonRelease-3>", self.zoom_out)
        self.canvas.pack()
        self.c_string = StringVar()
        self.c_string.set('')
        self.frame = Frame(self.window)
        self.c_gauge = Label(self.frame, textvar=self.c_string, width=20)
        self.c_gauge.pack(side=LEFT, anchor=W)
        self.iter_label = Label(self.frame, text='Iterates:')
        self.iter_label.pack(side=LEFT, anchor=SE)
        self.iter_slider = Scale(self.frame, orient=HORIZONTAL, length=300,
                                  from_=1, to_=300, resolution=1)
        self.iter_slider.set(200)
        self.iter_slider.bind("<ButtonRelease-1>", self.iterates)
        self.iter_slider.pack(side=LEFT, fill=X, anchor=W)
        self.frame.pack(side=BOTTOM)
        self.image = None
        self.index_line = None
        self.set(start, stop, c0, c1)
        
    def set(self, start = None, stop = None, c0=None, c1=None):
        if start != None: self.start = start
        if stop != None: self.stop = stop
        if c0 != None: self.c0 = c0
        if c1 != None: self.c1 = c1
        self.delta_c = max(MIN_DELTA, (self.c1 - self.c0)/self.width)
        for i in range(self.width):
            self.c_value[i] = self.c0 + i*self.delta_c
        
        imagestring = _chaos.orbiplot(self.width,self.height,self.start,self.stop,
                                    self.c0,self.c1)
        self.pyimage = Image.fromstring('L', (self.width, self.height), imagestring)
        self.bitmap = ImageTk.PhotoImage(self.pyimage)
        if self.image:
            self.canvas.delete(self.image)
        self.image = self.canvas.create_image(0, 0, anchor=NW, image=self.bitmap)
        self.window.title('Orbit diagram for %f < c < %f'%(self.c0, self.c1))

    def motion(self, event):
        if self.index_line :
            self.canvas.delete(self.index_line)
        self.index_line =  self.canvas.create_line(event.x, 0, event.x, self.height)
        try:
            self.c_string.set("c = %f"%self.c_value[event.x])
        except:
            pass
    
    def leave(self, event):
        if self.index_line :
            self.canvas.delete(self.index_line)
            self.dot = None
        self.c_string.set('')

    def mouse_down(self, event):
        self.x = event.x

    def mouse_up(self, event):
        if self.index_line and self.x != event.x:
            new_c0 = min(self.c_value[self.x], self.c_value[event.x])
            new_c1 = max(self.c_value[self.x], self.c_value[event.x])
            new_c1 = min(new_c1, 0.25)
            self.set(c0=new_c0, c1=new_c1)

    def zoom_out(self, event):
        if self.index_line:
            w = (self.c1 - self.c0)/2
            self.set(c0 = self.c0 - w, c1 = min(self.c1 + w, 0.25))

    def iterates(self, value):
        self.set(stop=self.start+self.iter_slider.get())
